package com.xiaoc.bulldozer.common.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.regex.Pattern;

import javax.annotation.Resource;

import com.xiaoc.bulldozer.common.model.Account;
import com.xiaoc.bulldozer.common.model.SendMessageLog;
import com.xiaoc.bulldozer.common.service.*;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.xc.framework.cache.manager.CacheManager;
import com.xc.framework.cache.utils.CacheUtils;
import com.xc.framework.common.exception.BusinessException;
import com.xc.framework.common.utils.DateUtil;
import com.xc.framework.common.utils.HttpUtil;
import com.xc.framework.common.utils.JacksonUtil;
import com.xiaoc.bulldozer.common.CacheKeys;
import com.xiaoc.bulldozer.common.ConfigKeys;
import com.xiaoc.bulldozer.common.Constant;
import com.xiaoc.bulldozer.common.ResponseCode;
import com.xiaoc.bulldozer.common.dto.SmtpHttpSubmitRsponse;
import com.xiaoc.bulldozer.common.dto.SmtpMessageDto;
import com.xiaoc.bulldozer.common.service.cache.CommonConfigCacheService;
import com.xiaoc.bulldozer.common.util.Md5Util;

@Service("smtpMessageService")
public class SmtpMessageServiceImpl implements SmtpMessageService {

    private Logger logger = LoggerFactory.getLogger(SmtpMessageServiceImpl.class);

    @Autowired
    private CloseableHttpClient httpClient;

    @Resource(name = "remoteCacheManager")
    private CacheManager remoteCacheManager;

    @Value("${run.mode}")
    private String runMode;

    @Resource(name = "commonConfigService")
    private CommonConfigCacheService commonConfigService;

    @Resource(name = "sendMessageLogService")
    private SendMessageLogService sendMessageLogService;

    @Resource(name = "accountService")
    private AccountService accountService;


    private static Pattern PHONE_PATTERN = Pattern.compile("1\\d{10}");

    @Override
    public void sendVerifyCode(String phoneNumber,String type) {

        phoneNumber = StringUtils.trimToNull(phoneNumber) ;

        if(phoneNumber == null || !PHONE_PATTERN.matcher(phoneNumber).matches()) {
            logger.error("phoneNumber error:" + phoneNumber);
            throw new BusinessException(ResponseCode.BUSINESS_ERROR.getCode(), "手机号格式有误");
        }

        SmtpMessageDto messageDto = (SmtpMessageDto) remoteCacheManager.get(CacheUtils.generateCacheKey(CacheKeys.PHONENUMBER_VERIFY_CODE_DTO_KEY, phoneNumber,Constant.SYSTEM_TYPE,type));

        if (messageDto != null) {
            long interval = System.currentTimeMillis() - messageDto.getSendTime();
            if (interval < Constant.MSG_SEND_TIMEOUT) {
                logger.error("phoneNumber:" + phoneNumber + " send verifyCode duplicated");
                throw new BusinessException(ResponseCode.BUSINESS_ERROR.getCode(), "验证码已发送，请勿重复获取");
            }
        }


        String msgCode = getRandNum(6);

        logger.info("phone:[{}]code:[{}]",phoneNumber,msgCode);
        String contentTemplate = commonConfigService.getValue(ConfigKeys.MESSAGE_VERIFY_CODE);

        String content = StringUtils.replace(contentTemplate, "{msgCode}", msgCode);

        messageDto = new SmtpMessageDto();
        messageDto.setPhoneNumber(phoneNumber);
        messageDto.setContent(msgCode);
        messageDto.setSendTime(System.currentTimeMillis());

        sendMessageSaveLog(phoneNumber, content, Integer.valueOf(type));
        remoteCacheManager.put(CacheUtils.generateCacheKey(CacheKeys.PHONENUMBER_VERIFY_CODE_DTO_KEY, phoneNumber,Constant.SYSTEM_TYPE,type), messageDto, Constant.MSG_VERIFYCODE_TIMEOUT);
    }

    /**
     *
     * @param phoneNumber 手机号
     * @param code 验证码
     * @param type 1：注册验证码 2：预约验证码 格式："bulldozer":phoneNumber:type
     * @return
     */
    @Override
    public boolean verifyCode(String phoneNumber, String code,String type) {

        phoneNumber = StringUtils.trimToNull(phoneNumber);

        if (StringUtils.equals(runMode, "dev")) {
            return true;
        }

        if (StringUtils.isEmpty(phoneNumber) || StringUtils.isEmpty(code)) {
            return false;
        }

        SmtpMessageDto messageDto = (SmtpMessageDto) remoteCacheManager.get(CacheUtils.generateCacheKey(CacheKeys.PHONENUMBER_VERIFY_CODE_DTO_KEY, phoneNumber,Constant.SYSTEM_TYPE,type));

        if (messageDto == null) {
            return false;
        }

        String msgCode = messageDto.getContent();

        boolean isValid = StringUtils.equals(code, msgCode);

//        if (isValid) {
//            remoteCacheManager.remove(CacheUtils.generateCacheKey(CacheKeys.PHONENUMBER_VERIFY_CODE_DTO_KEY, phoneNumber));
//        }

        return isValid;
    }
    
    @Value("${smtp.url}")
    private String smtpUrl;
    
    @Value("${smtp.username}")
    private String smtpUsername;
    
    @Value("${smtp.pwd}")
    private String smtpPwd;
    
    @Value("${smtp.servicecode}")
    private String smtpServicecode;
    
    @Value("${smtp.proxy.servicecode}")
    private String smtpProxyServicecode;
    
    @Value("${smtp.orgcode}")
    private String smtpOrgcode;
    
    @Value("${smtp.msgtype}")
    private String smtpMsgtype;
    
    @Value("${smtp.reportflag}")
    private String smtpReportflag;
    
    @Value("${smtp.priority}")
    private String smtpPriority;

    @Override
    public void sendMessage(String phoneNumber, String content) {

        if (StringUtils.equals(runMode, "dev")) {
            logger.info("开发环境下，不发短信");
            return;
        }

        String timeStamp = DateUtil.formatDate(new Date(), "yyyyMMddHHmmss");

        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
        nameValuePairs.add(new BasicNameValuePair("timestamp", timeStamp));
        nameValuePairs.add(new BasicNameValuePair("userName", smtpUsername));
        nameValuePairs.add(new BasicNameValuePair("sign", Md5Util.getMd5(smtpPwd + timeStamp)));
        nameValuePairs.add(new BasicNameValuePair("serviceCode", smtpServicecode));
        nameValuePairs.add(new BasicNameValuePair("phones", phoneNumber));
        nameValuePairs.add(new BasicNameValuePair("mhtMsgIds", RandomStringUtils.randomAlphabetic(1)));
        nameValuePairs.add(new BasicNameValuePair("sendTime", ""));
        nameValuePairs.add(new BasicNameValuePair("priority", smtpPriority));
        nameValuePairs.add(new BasicNameValuePair("orgCode", smtpOrgcode));
        nameValuePairs.add(new BasicNameValuePair("msgType", smtpMsgtype));
        nameValuePairs.add(new BasicNameValuePair("msgContent", content));
        nameValuePairs.add(new BasicNameValuePair("reportFlag", smtpReportflag));

        String httpResponseContent = HttpUtil.postRequestContent(httpClient, smtpUrl, nameValuePairs);

        logger.info("send message to " + "phoneNumber:" + phoneNumber + ", content:" + content + " with response:" + httpResponseContent);

        SmtpHttpSubmitRsponse submitResult = JacksonUtil.readValue(httpResponseContent, SmtpHttpSubmitRsponse.class);

        int result = submitResult.getResult();

        if (result != 0) {
            logger.error("send message to " + "phoneNumber:" + phoneNumber + ", content:" + content + " with response:" + httpResponseContent);
            throw new BusinessException(ResponseCode.BUSINESS_ERROR.getCode(), "短信发送失败");
        }
    }
    
    @Override
    public void sendMessageSaveLog(String phoneNumber, String content,Integer type) {

        if (StringUtils.equals(runMode, "dev")) {
            logger.info("开发环境下，不发短信");
            return;
        }

        String timeStamp = DateUtil.formatDate(new Date(), "yyyyMMddHHmmss");

        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
        nameValuePairs.add(new BasicNameValuePair("timestamp", timeStamp));
        nameValuePairs.add(new BasicNameValuePair("userName", smtpUsername));
        nameValuePairs.add(new BasicNameValuePair("sign", Md5Util.getMd5(smtpPwd + timeStamp)));
        nameValuePairs.add(new BasicNameValuePair("serviceCode", smtpServicecode));
        nameValuePairs.add(new BasicNameValuePair("phones", phoneNumber));
        nameValuePairs.add(new BasicNameValuePair("mhtMsgIds", RandomStringUtils.randomAlphabetic(1)));
        nameValuePairs.add(new BasicNameValuePair("sendTime", ""));
        nameValuePairs.add(new BasicNameValuePair("priority", smtpPriority));
        nameValuePairs.add(new BasicNameValuePair("orgCode", smtpOrgcode));

        if (type.equals(1) || type.equals(2)) {
            logger.info("通知类短信");
            nameValuePairs.add(new BasicNameValuePair("msgType", "03"));
        } else {
            if (commonConfigService.getValue(ConfigKeys.IS_SEND_MARKET).equals(Constant.ONE.toString())) {
                logger.info("营销类短信");
                nameValuePairs.add(new BasicNameValuePair("msgType", "04"));
            } else {
                logger.info("不发营销类短信");
                return;
            }


        }
        nameValuePairs.add(new BasicNameValuePair("encoding", "utf-8"));
        nameValuePairs.add(new BasicNameValuePair("msgContent", content));
        nameValuePairs.add(new BasicNameValuePair("reportFlag", smtpReportflag));

        String httpResponseContent = HttpUtil.postRequestContent(httpClient, smtpUrl, nameValuePairs);

        logger.info("send message to " + "phoneNumber:" + phoneNumber + ", content:" + content + " with response:" + httpResponseContent);

        SmtpHttpSubmitRsponse submitResult = JacksonUtil.readValue(httpResponseContent, SmtpHttpSubmitRsponse.class);

        int result = submitResult.getResult();
        SendMessageLog sendMessageLog = new SendMessageLog();
        Date date = new Date();
        sendMessageLog.setCreateTime(date.getTime());
        sendMessageLog.setType(type);
        sendMessageLog.setReceiver(phoneNumber);
        sendMessageLog.setContent(content);

        if (result != 0) {
            sendMessageLog.setResult(submitResult.getDesc());
            sendMessageLog.setStatus(0);
            sendMessageLogService.save(sendMessageLog);
            logger.error("send message to " + "phoneNumber:" + phoneNumber + ", content:" + content + " with response:" + httpResponseContent);
            logger.info("发送短信失败{}",ResponseCode.BUSINESS_ERROR.getCode());
            //            throw new BusinessException(ResponseCode.BUSINESS_ERROR.getCode(), "短信发送失败");
        } else {
            sendMessageLog.setResult("成功");
            sendMessageLog.setStatus(1);
            sendMessageLogService.save(sendMessageLog);
        }
    }

    @Override
    public String getRandNum(int charCount) {

        String charValue = "";
        for (int i = 0; i < charCount; i++) {
            char c = (char) (randomInt(0, 10) + '0');
            charValue += String.valueOf(c);
        }
        
        return charValue;
    }

    @Override
    public void clearVerifyCode(String phoneNumber) {
        remoteCacheManager.remove(CacheUtils.generateCacheKey(CacheKeys.PHONENUMBER_VERIFY_CODE_DTO_KEY, phoneNumber));
    }

    private int randomInt(int from, int to) {
        Random r = new Random();
        return from + r.nextInt(to - from);
    }

}
